#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/conf.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<netdb.h>
#define FALSE 0
#define TRUE 1
#define INIT_SIZE 1
#define HOSTNAME_SIZE 100
#define IP_LEN 16
#define WAIT_TIME_MS 500
#define BRO_PORT 8080

void fail(char *);
char * chomp(char *);
char * contactBros(char *, char *);

void fail(char * msg)
{
	if(errno)
	{
		perror(msg);
	}
	else
	{
		fprintf(stderr, msg);
		fprintf(stderr, " error\n");
	}
	exit(1);
}

char * chomp(char * str_begin)
{
	char * str = str_begin;

	if(!str)
		fail("chomp");

	while(*str)
		if(*str == '\n' && *(str+1) == '\0')
		{
			*str = '\0';
			break;
		}
		else
			str++;

	return str_begin;
}

/********************************************************************************
Assume that the file is in the format:

www.bankofamerica.com
www.wamu.com
www.andrew.com
etc.
********************************************************************************/
char * DNSCOMP(char * hostname, char * filename, char * friends_file) //add in the response we received from our DNS server
{
	int name_found = FALSE;
	int hostname_len = strlen(hostname);

	//open the file
	FILE * securehosts_file = fopen(filename, "r");
	if(errno)
		fail("fopen");

	//allocate zero-ed buffer
	char * curr_hostname = (char *)calloc(1, HOSTNAME_SIZE);
	if(!curr_hostname)
		fail("calloc");

	while(!feof(securehosts_file))
	{
		//get the current host name
		fgets(curr_hostname, HOSTNAME_SIZE+1, securehosts_file);
		if(!curr_hostname)
			fail("fgets");

		//quit if ferror
		if(ferror(securehosts_file))
			fail("secure hosts file");

		//if a match is found
		if(strcmp(hostname, chomp(curr_hostname)) == 0)
		{
			name_found = TRUE;	
			break;
		}

		//zero out the current hostname
		bzero(curr_hostname, HOSTNAME_SIZE);
	}

	//close the file
	fclose(securehosts_file);

	//ask your bros if neccesary
	return name_found ? contactBros(hostname, friends_file) : NULL;
}

char * contactBros(char * hostname, char * friends_file)
{
	char * ip_found = NULL;
	char * curr_ip = NULL;
	char ** reply_array;
	ssize_t addr_len;
	ssize_t bytes_received;
	int array_size = INIT_SIZE;
	int index = 0;

	struct sockaddr_in dest_addr;
	struct sockaddr_in incoming_addr;
	memset(dest_addr.sin_zero, '\0', sizeof(dest_addr.sin_zero));

	//open the file
	FILE * friends_list = fopen(friends_file, "r");
	if(errno)
		fail("fopen");

	//allocate the array
	reply_array = (char **)malloc(array_size * sizeof(char *));
	if(!reply_array)
		fail("malloc");

	//allocate for current IP
	curr_ip = (char *)calloc(1, IP_LEN);
	if(!curr_ip)
		fail("calloc");

	//open a new socket for UDP
	int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sock_fd == -1)
		fail("socket");

	//send out UDP packets to all friends on the friends_list
	while(!feof(friends_list))
	{
		//get the current host name
		fgets(curr_ip, IP_LEN, friends_list);
		if(!curr_ip)
			fail("fgets");

		//configure the destination
		dest_addr.sin_family = AF_INET;
		dest_addr.sin_port = htons(BRO_PORT);
		inet_aton(chomp(curr_ip), &(dest_addr.sin_addr));

		//send packet to bro
		if(sendto(sock_fd, hostname, strlen(hostname), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) == -1)
			fail("send");

		//allocate the next slot in the array
		reply_array[index] = (char *)calloc(1, IP_LEN);
		if(!reply_array[index])
			fail("calloc");

		//wait to receive from bro
		bytes_received = recvfrom(sock_fd, reply_array[index], IP_LEN, 0, (struct sockaddr *)&incoming_addr, (socklen_t *)&addr_len);
		if(bytes_received == -1)
			fail("recvfrom");

		//quit if ferror
		if(ferror(friends_list))
			fail("friends list");

		//zero out the current IP buffer and incoming_addr
		bzero(curr_ip, IP_LEN);
		bzero(&incoming_addr, sizeof(incoming_addr));

		//increment the counter
		index++;

		//if needed, double the size of the array
		if(index > array_size)
		{
			array_size *= 2;
			reply_array = (char **)realloc(reply_array, array_size * sizeof(char *));
			if(!reply_array)
				fail("realloc");
		}
	}

	//close the socket
	close(sock_fd);

	//consolidate the responses (simple majority?)

	fclose(friends_list);

	//free all the memory we allocated
	for(; index > 0; index--)
		free(reply_array[index]);

	free(reply_array);

	//return the the legitimate IP address; else NULL
	return ip_found;	
}

int main(int argc, char ** argv)
{
	DNSCOMP("www.bankofamerica.com", "foo.txt", "bros.txt");
	return 0;
}
